#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <numeric>
using namespace std;

int dfs(vector<vector<int>> &gh, vector<int> &vis, int u, stack<int> &seq)
{
	vis[u] = 1;
	for (auto v : gh[u]) {
		if (!vis[v]) {
			dfs(gh, vis, v, seq);
		}
	}
	seq.push(u);
	return 0;
}

int solv_dfs(vector<vector<int>> &gh, int n)
{
	stack<int> seq, path;
	vector<int> vis(n + 1, 0);
	for (int i = 1; i <= n; i++) {
		if (!vis[i]) {
			dfs(gh, vis, i, seq);
		}
	}

	int ans = 0;
	fill(vis.begin(), vis.end(), 0);
	while (!seq.empty()) {
		int u = seq.top();
		seq.pop();
		if (!vis[u]) {
			ans += 1;
			dfs(gh, vis, u, path);
		}
	}
        return ans;
}

int find(vector<int> &pa, int x)
{
	return pa[x] == x ? x : pa[x] = find(pa, pa[x]);
}

int merge(vector<int> &pa, int x, int y)
{
	int fx = find(pa, x);
	int fy = find(pa, y);
	if (fy != fx) {
		pa[fx] = fy;
		return 1;
	} else {
		return 0;
	}
}

int solv_unset(vector<vector<int>> &gh, int n)
{
        vector<int> vis(n + 1, 0);
        vector<int> father(n + 1, 0);
        iota(father.begin(), father.end(), 0);
        for(int i = 1; i <= n; i++){
                for(auto v : gh[i]){
                        if(!vis[v]){
                                merge(father, i, v);
                                vis[v] = 1;
                        }
                }
        }
        set<int> uset;
        for(int i = 1; i <= n; i++){
                uset.insert(find(father, i));
        }
        return uset.size();
}

int main()
{
	int n = 0;
	cin >> n;
	vector<vector<int>> gh(n + 1);
	for (int i = 1; i <= n; i++) {
		int v;
		for (;;) {
			cin >> v;
			if (v == 0) {
				break;
			}
			gh[i].push_back(v);
		}
	}
	int ans = solv_unset(gh, n);
	cout << ans << endl;
	return 0;
}
/*
3
2 0
0
2 0
*/